//
//  ST_PrivateChatViewController.swift
//  BTVideo
//
//  Created by DouLei on 2019/7/20.
//  Copyright © 2019 DouLei. All rights reserved.
//

import UIKit
import SwifterSwift
import MJRefresh
import NIMSDK
import RealmSwift
import SwiftyJSON
import SwiftyUserDefaults
import SwiftyAttributes
import RxSwift
import RxCocoa


/**
 不能发送消息
 */
enum ST_PREVENT_CHAT_ENUM:Int{
    
    /**
     正常
     */
    case noraml
    /**
     需要检测真人
     */
    case verifyFace
}

enum ST_PRESENT_ALERT_ENUM {
    case FaceDetected
    case MemberSubscribe
    case remoteConfine
}


class ST_PrivateChatViewController: ST_BTLightBarViewController {
    
    var dismiss_oper = false
    
    deinit {
        
        NotificationCenter.default.removeObserver(self)
        
        print("聊天会话 释放问题")
    }
    
    override func left_click() {
        
        if self.other_chat_source ?? 0 > 0{
            
            JVrequest(PH.unlikePersonApi,parameters:["target_accid":self.sessionID],success: { (json) in
                
                print("碰一碰不喜欢成功")
            }) { (code, err) in
                
                print("碰一碰不喜欢失败:",err)
            }
        }
        
        
        if dismiss_oper{
            self.navigationController?.dismiss(animated: false, completion: nil)
        }else{
            goback_previous_controller()
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        self.last_play_audio_cell?.stop_play_audio()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        read_all_msg = false
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        //        ST_BTLaunchController.shared.hiddenTabbar()
        ST_DTChatFeed.shared.chatAloneVC = self
        
        read_all_msg = true
        
        ST_ConversationAdapter.shared.mark_read(sessionId: sessionID)
    }
    
    var send_talk_o_k = false
    
    var read_all_msg = true
    
    
    fileprivate var send_requre_coin:Int?
    
    fileprivate var is_friends:Bool?
    
    fileprivate var her_wechat:String?
    
    fileprivate var her_unlock_wechat_level:Int?
    
    fileprivate var her_unlock_wechat_level_string:String?
    
    fileprivate var intimacy_with_me_wechat_level:Int?
    
    fileprivate var last_lock_media_talk:Bool?
    
    fileprivate var lock_media_talk = true{
        didSet{
            
            //            已经解锁，并且是更新的时候
            if let last = last_lock_media_talk,last != lock_media_talk,lock_media_talk == false {
                
                let tipsMsg = ST_DTChatMessage()
                tipsMsg.cellStyle = .unlockCallTips
                tipsMsg.figureFrame()
                self.append_model(tipsMsg)
                
            }
            
            
            last_lock_media_talk = lock_media_talk
        }
    }
    
    var prevent_chat = ST_PREVENT_CHAT_ENUM.noraml
    
    func start_add_notification(){
        
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: OperationQueue.main) {[weak self] (notification) in
            
            self?.key_broad_height_changed(notification: notification)
            
        }
        
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: OperationQueue.main) {[weak self] (notification) in
            
            if self?.inputBar.heightStatus == .keybroad{
                self?.inputBar.heightStatus = .normal
                self?.changeFrame()
            }
        }
        
        NotificationCenter.default.addObserver(self, selector: #selector(update_local_msg_ext_handle(notification:)), name: Notification.Name.i_m_message_local_ext_updated, object: nil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(refresh_guard_noti_handle(nofi:)), name: Notification.Name.sendGuard, object: nil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(refresh_present_alert_status), name: Notification.Name.face_status, object: nil)
        
        //        NotificationCenter.default.addObserver(self, selector: #selector(refresh_present_alert_status), name: Notification.Name.in_pur_status_success), object: nil)
        
        
        NotificationCenter.default.addObserver(self, selector: #selector(goback_topmost_controller_handle(noti:)), name: Notification.Name.goback_topmost_controller, object: nil)
    }
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        self.own_navigation_bar.addSubview(member_title_view)
        
        member_title_view.snp.makeConstraints { (make) in
            make.center.equalTo(self.title_nav_btn)
            make.height.equalTo(44)
        }
        
        
        self.right_nav_btn.setImageForAllStates(ST_ImageUtils.imageName("消息_icon_更多_1")!)
        
        //        self.inputBar.back_image_view.isHidden = true
        
        //        self.view.addSubview(tableView)
        //        self.view.addSubview(inputBar)
        if !hidden_right_btn {
            
            own_navigation_bar.addSubview(banBtn)
            
            banBtn.snp.makeConstraints { (make) in
                make.bottom.equalToSuperview()
                make.height.equalTo(44)
                make.width.equalTo(30)
                make.right.equalToSuperview().offset(-55)
            }
        }
        
        
        self.view.insertSubview(tableView, belowSubview: own_navigation_bar)
        if sessionID != SMART_ASSISTANT_SESSION_ID{
            self.view.insertSubview(inputBar, belowSubview: own_navigation_bar)
            self.view.insertSubview(tips_label, belowSubview: own_navigation_bar)
            tips_label.snp.makeConstraints { (make) in
                make.left.equalToSuperview().offset(15)
                make.right.equalToSuperview().offset(-20)
                make.bottom.equalTo(self.inputBar.snp.top).offset(-10)
            }
            
            inputBar.snp.makeConstraints { (make) in
                make.left.right.equalTo(self.view)
                make.bottom.equalTo(self.view)
                make.height.equalTo(ST_BTChatInputBar.normal_height)
            }
        }
        
        
        self.tableView.snp.makeConstraints { (make) in
            make.top.equalTo(own_navigation_bar.snp.bottom).offset(2)
            make.left.right.equalTo(self.view)
            if sessionID == SMART_ASSISTANT_SESSION_ID {
                make.bottom.equalToSuperview()
            }else{
                make.bottom.equalTo(self.inputBar.snp.top)
            }
        }
        
        
        
        
        record_audio_sign_view.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 120, height: 120))
        
        record_audio_sign_view.center =  self.view.center
        
        record_audio_sign_view.addSubview(speak_power_view)
        //
        speak_power_view.frame = CGRect.init(x: 37, y: 28, width: 46, height: 46)
        
        
        start_add_notification()
        
        self.load_newest_message()
        
        
        self.view.addSubview(record_audio_sign_view)
        
        if sessionID != SMART_ASSISTANT_SESSION_ID{
            bind_input_bar_event_handle()
        }
        
        request_with_handle()
    }
    
    func bind_input_bar_event_handle(){
        //        Closure
        inputBar.modify_height_status = { [weak self] in
            self?.changeFrame()
        }
        
        inputBar.ask_wechat_closure = { [weak self] in
            
            guard let strongSelf = self,let numberStr = strongSelf.her_wechat else {
                
                self?.toast(text: "对方还未设置微信号")
                
                return
            }
            
            guard let unlock = strongSelf.her_unlock_wechat_level,let current = strongSelf.intimacy_with_me_wechat_level , let unlockStr = strongSelf.her_unlock_wechat_level_string else{
                return
            }
            
            if current < unlock{
                
                let alert = BTVerticalAlertViewController.createUnlockWechatAlert(propName: unlockStr)
                
                alert.confirm_closure = {
                    self?.show_goods_handle()
                }
                
                GlobalPresent(toController: alert)
                
            }else{
                
                ST_DTChatFeed.shared.sendSimulateWechatNumberMessage(sessionId: strongSelf.sessionID, anotherWechat: numberStr)
            }
            
        }
        
        inputBar.send_text_closure = { [weak self] text in
            
            self?.send_text_message(text: text)
            
        }
        
        inputBar.send_emoji_closure = { [weak self] emoji in
            
            self?.send_emoji_message(emoji: emoji)
            
        }
        
        
        inputBar.send_image_closure = { [weak self] thumbnailPath,imagePath,size,isSnap in
            
            self?.send_image_message(thumbnailPath: thumbnailPath, imagePath: imagePath,size:size,isSnapChat:isSnap)
        }
        
        inputBar.send_video_closure = {  [weak self] thumbnailPath,size,videoPath in
            
            
            self?.send_video_message(thumbnailPath: thumbnailPath, size: size, videoPath: videoPath)
        }
        
        inputBar.present_goods_closure = {[weak self] in
            self?.show_goods_handle()
        }
        
        inputBar.require_detect_closure = {[weak self] in
            
            self?.require_detect_handle()
        }
        
        inputBar.request_media_talk_closure = {[weak self] in
            
            self?.media_talk_options_handle()
        }
        
        
        //        send_red_packet_closure
        
        inputBar.send_red_packet_closure = {[weak self] coin,text in
            
            
            JVrequest(PH.sendRedPacketApi, parameters: ["target_accid":self?.session.sessionId ?? "","money":coin,"remark":text], queue: nil,success:{ (json) in
                
                let model = ST_Custom255AttachmentModel()
                
                model.type = 0
                
                model.redPacketId = json["data"]["red_packet_id"].stringValue
                
                model.redPacketCoinNum = coin.int
                
                model.redPacketIncome = json["data"]["income"].floatValue
                
                model.redPacketTxt = text
                
                if let last = ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sweet_coin{
                    
                    ST_BTUserInfoManager.shared.modify_sweet_coin(value: last - coin)
                    
                }
                
                
                /*
                 var redPacketId:String = ""
                 var redPacketCoinNum:Int = 0
                 var redPacketIncome:Float = 0
                 var redPacketTxt: String = ""
                 var goodsId: String = ""
                 var title: String = ""
                 var subTitle: String = ""
                 var imageUrl: String = ""
                 */
                
                self?.sendRedPacketMessage(attach: model)
                
                
            }, failure: { (code, err) in
                
                self?.toast(text: err)
            })
            
            
            
            
        }
        
        //        录制 需要外部UI 参与
        inputBar.recordAudioDelegate = self
    }
    
    func request_with_handle(){
        
        member_info_request()
        
        pull_intimacy()
        
    }
    
    
    fileprivate lazy var member_title_view:ST_ChatTitleView = {
        let control = ST_ChatTitleView()
        return control
    }()
    
    fileprivate func setTableHeaderView(headerView:UIView?){
        
        if Defaults[.isPanda] {
            return
        }
        
        if data.count < 15{
            if let v = headerView{
                self.tableView.tableHeaderView = v
                d_tscroll_table_view_to_bottom()
            }
        }
    }
    
    fileprivate func expend_coin_tips(){
        
        if Defaults[.isPanda]{
            
            self.tips_label.isHidden = true
            
            return
        }
        
        
        if self.data.count > 0{
            self.tips_label.isHidden = true
        }else{
            
            //                    需要币聊天 并且 不是朋友
            if self.send_requre_coin ?? -219393 >= 0 && self.is_friends == false && ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .male{
                self.tips_label.attributedText = pay_tips_first_accost_string
            }else{
                self.tips_label.attributedText = normal_first_accost_string
            }
            
            self.tips_label.isHidden = false
        }
    }
    
    func layout_header_view(list:[ST_ChatUserST_PeculiarityCellModel]){
        
        if let matchedModel = matched_header_model{
            
            self.tips_label.isHidden = true
            
            self.matched_header_view.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: ScreenWidth, height: matchedModel.header_height))
            
            self.matched_header_view.model = matchedModel
            
            self.setTableHeaderView(headerView: self.matched_header_view)
            
            self.expend_coin_tips()
        }else{
            
            if SYSTEM_SESSION_SET.contains(self.sessionID){
                return
            }
            
            if display_chat_tips{
                
                self.tips_label.isHidden = true
                
                self.headerView.ownArray = list
                
                let height:CGFloat = list.count > 0 ? 267+110 : 267
                
                self.headerView.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: ScreenWidth, height: height))
                
                self.setTableHeaderView(headerView: self.headerView)
                
                self.headerView.push_user_center_closure = {[weak self] in
                    self?.push_user_controller_handle()
                }
            }else{
                
                //                功能 #4519 需求
                if ChatTipsForMeView.display_tips_for_me() == false{
                    self.setTableHeaderView(headerView: nil)
                }else{
                    
                    self.tips_header_view.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: ScreenWidth, height: self.tips_header_view.figured_height))
                    
                    self.setTableHeaderView(headerView: self.tips_header_view)
                }
                
                
                self.expend_coin_tips()
            }
        }
    }
    
    var matched_header_model:ST_ChatMatchedViewModel?
    
    var other_chat_source:Int?
    
    var display_chat_tips = false
    
    var disposeBag = DisposeBag()
    /**
     当前不能聊天Alert
     */
    var presentAlert:(type:ST_PRESENT_ALERT_ENUM,alert:BTVerticalAlertViewController)?
    
    
    fileprivate func pull_intimacy(){
        
        if SYSTEM_SESSION_SET.contains(sessionID){
            return
        }
        
        JVrequest(PH.currIntimacyProgressApi,parameters: ["target_accid":self.sessionID]) { (json) in
            
            let nextImageUrl = json["data"]["next_intimacy"]["image"].stringValue
            
            let curr = json["data"]["current_intimacy"].floatValue
            
            let total = json["data"]["total_intimacy"].floatValue
            
            var progress:CGFloat
            
            if total == 0{
                progress = 0
            }else{
                progress = curr.cgFloat/total.cgFloat
            }
            
            if self.next_intimacy_percentage_view.superview == nil{
                self.view.addSubview(self.next_intimacy_percentage_view)
                self.next_intimacy_percentage_view.snp.makeConstraints { make in
                    make.right.equalToSuperview().offset(-15+(76-50)/2.0)
                    make.top.equalToSuperview().offset(58+44+statusBarHeight-(76-50)/2.0)
                    make.width.equalTo(76)
                    make.height.equalTo(76)
                }
            }
            
            //            self.next_intimacy_percentage_view.bind(progress: 0.94, url: nextImageUrl)
            
            self.next_intimacy_percentage_view.bind(progress: progress, url: nextImageUrl)
            
            //            print("bug 000189891:\(Date()) 当前=",curr,"----total=",total)
            
        } failure: { (code, error) in
            
            self.toast(text: error)
        }
    }
    
    fileprivate func member_info_request(){
        
        //        print("本地时间:",Date(),"--Begin")
        //        fetchNobleStatus()
        
        if SYSTEM_SESSION_SET.contains(sessionID){
            
            if let info = BINP.fetch_nickname_with_avatar(userId: sessionID){
                self.chatTitle = info.userName
            }
            
            self.member_title_view.model = ST_ChatTitleViewModel(nickname: self.chatTitle, isVip: false, isGoddess: false, isNoble: false, icon: nil)
            
            return
        }
        
        
        var param = ["target_accid":self.sessionID]
        
        if let chatSource = self.other_chat_source{
            param.updateValue(chatSource.string, forKey: "source")
        }else{
            param.updateValue("0", forKey: "source")
        }
        
        JVrequest(PH.getTalkMemberInfoApi,parameters:param,success: { (json) in
            
            let data = json["data"]
            
            //            print("本地时间:",Date(),"--End")
            print("gettalkMember---",data)
            
            self.lock_media_talk = !data["can_point_talk"].boolValue
            
            self.send_requre_coin = data["talk_coin"].intValue
            
            self.another_gender = data["gender"].intValue
            
            self.is_friends = data["is_friend"].boolValue
            
            if let wechat = data["target_wechat"].string,wechat.count > 2{
                self.her_wechat = wechat
            }
            
            self.her_unlock_wechat_level = data["target_free_intimacy"].intValue
            
            self.her_unlock_wechat_level_string = data["target_free_intimacy_name"].stringValue
            
            self.intimacy_with_me_wechat_level = data["intimacy"].intValue
            
            
            var talk_coin = data["talk_coin"].floatValue
            
            if let unlock = self.her_unlock_wechat_level,let current =  self.intimacy_with_me_wechat_level , current >= unlock{
                talk_coin = 0
            }
            
            ST_DTChatMessageSendHander.shared.setObserver(sessionId: self.sessionID, send_requre_coin: talk_coin, delegate: self)
            
            self.bind_other_data(data: data)
            
            self.chat_user_face_status = data["face_audit_state"].intValue
            
            if data["is_invite_face"].boolValue{
                self.prevent_chat = .verifyFace
            }
            
            if data["block_state"].intValue != 1{
                
                ToastHud(text: data["message"].stringValue, view: self.view)
                
                ST_ConversationAdapter.shared.delete_recent_conversation(sessionId: self.sessionID)
                
                
                main_thread_execute(afterDelay: 1.5) {
                    self.goback_previous_controller()
                }
                
                return
            }
            /* 版本号验证不需要了
             else if data["is_satisfy_version"].boolValue == false{
             
             ToastHud(text: data["message"].stringValue, view: self.view)
             
             main_thread_execute(afterDelay: 1.5) {
             self.goback_previous_controller()
             }
             
             return
             }*/
            //            1 是匹配聊天
            if data["source"].intValue == 1{
                
                self.matched_header_model = ST_ChatMatchedViewModel.init(json: data)
            }
            
            let featureList = data["target_feature"].arrayValue.map { (itemJson) -> ST_ChatUserST_PeculiarityCellModel in
                return ST_ChatUserST_PeculiarityCellModel.init(fromJson: itemJson)
            }
            
            self.layout_header_view(list: featureList)
            
            if data["can_receive_source"].intValue != 1{
                self.inputBar.onlyText = true
            }else{
                self.inputBar.onlyText = false
            }
            
            
            //            if ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex?.rawValue == self.another_gender,SCComponets.rich_text_storage_component.json["confine_private"].type != .null{
            //
            //                self.remote_confinetalk_toast()
            //
            //
            //                return
            //            }
            
            
            //        1.开启认证和会员可以同时开启，组合判断，2个条件都需要
            //    2个都开启的情况，先判断真人认证，再判断会员
            if data["only_face_talk"].intValue == 1 && FACE_AVATAE_STATE != 3{
                self.toast_detect_face()
                return
            }
            
            if data["only_vip_talk"].intValue == 1 && FETCH_MEMBER_STATUS() != .subscribe{
                self.toast_require_member()
                return
            }
            
            
            //
        }) { (code, error) in
            
            self.toast(text: error)
            
            main_thread_execute(afterDelay: 1.5) {
                self.left_click()
            }
            
        }
        
    }
    
    @objc fileprivate func goback_topmost_controller_handle(noti:Notification){
        
        if let toController = noti.userInfo?["controller"] as? UIViewController{
            
            if toController == self.presentAlert?.alert{
                
                refresh_present_alert_status()
                
            }
        }
    }
    
    
    @objc fileprivate func refresh_present_alert_status(){
        
        guard let alertStruct = self.presentAlert else { return }
        
        switch alertStruct.type {
        case .FaceDetected:
            if FACE_AVATAE_STATE == 3{
                
                alertStruct.alert.goback_previous_controller()
                
                self.presentAlert = nil
            }
        case .MemberSubscribe:
            if FETCH_MEMBER_STATUS() == .subscribe{
                
                alertStruct.alert.goback_previous_controller()
                
                self.presentAlert = nil
            }
        case .remoteConfine:
            break
        }
        
        
    }
    
    fileprivate func pay_for_remote_confine(){
        
        guard let current_user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else { return  }
        
        if current_user.sweet_coin < 1500{
            
            ST_MaidWayManager.shared.source =  .聊天充币
            
            ST_RechargeViewController.toast()
            
            return
        }
        
        self.presentAlert?.alert.show_indeterminate_h_u_d()
        
        JVrequest(PH.sameSexTalkApi,parameters: ["target_accid":sessionID]) { (json) in
            
            
            ST_BTUserInfoManager.shared.modify_sweet_coin(value: json["data"]["sweet_currency"].floatValue)
            
            self.presentAlert?.alert.hidden_indeterminate_h_u_d()
            
            self.presentAlert?.alert.goback_previous_controller()
            
        } failure: { (code, err) in
            
            self.presentAlert?.alert.toast(text: err)
        }
        
        
        
    }
    
    
    fileprivate func remote_confinetalk_toast(){
        
        let alert = BTVerticalAlertViewController.createChatRequireRechargeAlert()
        
        alert.dismiss_after_action = false
        
        alert.cancel_closure = {[weak self] in
            self?.left_click()
        }
        
        alert.confirm_closure = {
            
            self.pay_for_remote_confine()
            
        }
        
        self.presentAlert = (type:.remoteConfine,alert:alert)
        
        GlobalPresent(toController: alert)
        
        
    }
    
    
    fileprivate func more_person_talk_toast_require_member(){
        
        let alert = BTVerticalAlertViewController.createRequireMemberForTooMoreTalkAlert()
        
        alert.dismiss_after_action = false
        
        alert.cancel_closure = {[weak self] in
            self?.left_click()
        }
        
        alert.confirm_closure = {
            
            ST_MaidWayManager.shared.source = .聊天门槛_会员
            
            let vc  = ST_MemberSubscriberController.init(subscribeType: ST_BitianSubscribeType.无线喜欢次数)
            
            vc.overCurrentContext = true
            
            GlobalPresent(toController: vc)
            
            
        }
        
        self.presentAlert = (type:.MemberSubscribe,alert:alert)
        
        GlobalPresent(toController: alert)
        
        
    }
    
    fileprivate func toast_require_member(){
        
        
        let alert = BTVerticalAlertViewController.createRequireMemberForTalkAlert()
        
        alert.dismiss_after_action = false
        
        alert.cancel_closure = {[weak self] in
            self?.left_click()
        }
        
        alert.confirm_closure = {
            
            ST_MaidWayManager.shared.source = .对方要求是会员才能聊天
            
            let vc  = ST_MemberSubscriberController.init(subscribeType: ST_BitianSubscribeType.无线喜欢次数)
            
            vc.overCurrentContext = true
            
            GlobalPresent(toController: vc)
        }
        
        self.presentAlert = (type:.MemberSubscribe,alert:alert)
        
        GlobalPresent(toController: alert)
        
    }
    
    fileprivate func toast_detect_face(){
        
        
        
        let alert = BTVerticalAlertViewController.createDetectFaceForTalkAlert()
        
        alert.dismiss_after_action = false
        
        alert.cancel_closure = {[weak self] in
            self?.left_click()
        }
        
        
        
        self.presentAlert = (type:.FaceDetected,alert:alert)
        
        alert.confirm_closure = {
            
            if FACE_AVATAE_STATE == 2{
                
                let failure = ST_MatchFaceFailureController()
                
                failure.overCurrentContext = true
                
                GlobalPresent(toController: failure)
                
            }else if FACE_AVATAE_STATE != 3{
                
                DetectFaceHandle()
            }
        }
        
        GlobalPresent(toController: alert)
        
    }
    
    fileprivate func bind_other_data(data:JSON){
        
        BINP.save_gradient_effect_struct(accid: sessionID, nobleLevel: data["nobility"]["id"].intValue, nobleUrl: data["nobility"]["image"].stringValue)
        
        if data["is_goddess"].boolValue{
            BINP.update_goddess(accid: sessionID)
        }
        
        
        tableView.visibleCells.forEach({ ($0 as? ST_DTChatTextCell)?.refresh_text_bubble_effect() })
        
        
        self.headerView.bind(age: data["age"].intValue, address: data["address"].stringValue, face_status: data["face_audit_state"].intValue , myRequireCoin: data["my_talk_coin"].intValue)
        
        self.intimacyImage = data["intimacy_image"].string
        
        let userTitle:String
        if let remark = data["remark"].string,remark.count > 0{
            userTitle = remark
        }else{
            userTitle = data["nickname"].stringValue
        }
        
        self.chatTitle = userTitle
        
        
        self.member_title_view.model = ST_ChatTitleViewModel(nickname: userTitle, isVip: CHECK_MEMBER_STATUS(expirationTime: data["vip_expire"].intValue) == .subscribe, isGoddess: data["is_goddess"].boolValue, isNoble: data["nobility"]["id"].intValue > GradientEffectStruct.ORIGINAL_NOBLE_ID, icon: self.intimacyImage)
        
        if let url = self.intimacyImage{
            
            let key = Defaults[.currentUserID] + self.sessionID
            let chatSession = ST_BTChatSessioninfo()
            chatSession.chatSession = key
            chatSession.shipURL = url
            
            let realm = try! Realm()
            try! realm.write {
                realm.add(chatSession, update: Realm.UpdatePolicy.all)
            }
        }
        
        
        
        
        self.guardURL = AVATAR_SUPPLEMENT(guardTime: data["guard_time"].intValue, guardContent: data["guard_content"].stringValue)?.url
        
    }
    
    @objc fileprivate func refresh_guard_noti_handle(nofi:Notification){
        
        let json = JSON.init(nofi.userInfo ?? "")
        
        if json["userId"].stringValue != self.sessionID{
            return
        }
        
        self.guardURL = AVATAR_SUPPLEMENT(guardTime: json["guardTime"].intValue, guardContent: json["guardContent"].stringValue)?.url
        
    }
    
    fileprivate func refresh_guard(){
        
        self.tableView.visibleCells.forEach { (cell) in
            
            guard let iCell = cell as? ST_DTChatCell else{
                return
            }
            
            iCell.icon_supplement_u_r_l = self.guardURL
            
        }
    }
    
    
    // MARK: - load Data
    var pageSize = 20
    
    var first_scroll_bottom = true
    
    //    var originalImageArray = [ST_SKPhoto]()
    //
    //    var originalImageUUIDArray = [String]()
    
    func load_history_message(){
        
        
        
        guard let firstMsg = self.data.first  else {
            self.tableView.mj_header?.endRefreshing()
            return
        }
        
        let firstNIMMsg = NIMSDK.shared().conversationManager.messages(in: self.session, messageIds: [firstMsg.uuid])?.first
        
        guard let list = NIMSDK.shared().conversationManager.messages(in: session, message: firstNIMMsg, limit: self.pageSize) else{
            self.tableView.mj_header?.endRefreshing()
            return
        }
        
        if list.count < self.pageSize{
            
            let option = NIMHistoryMessageSearchOption()
            
            option.limit = UInt(self.pageSize)
            
            if let first = list.first{
                
                option.endTime = first.timestamp
                option.currentMessage = first
            }else if let localFirst = firstNIMMsg{
                option.endTime = localFirst.timestamp
                option.currentMessage = localFirst
            }
            
            option.sync = true
            
            NIMSDK.shared().conversationManager.fetchMessageHistory(self.session, option: option) {[weak self] (error, historyList) in
                
                if let rList = historyList{
                    
                    //                                                    for item in rList{
                    //                                                        print("historyList 每条消息的时间---",item.timestamp)
                    //                                                    }
                    
                    let dataList = rList.reversed() + list
                    
                    self?.handleMessage(list: dataList, loadHistory: true)
                    
                }else{
                    
                    self?.handleMessage(list: list, loadHistory: true)
                }
                
                if let err = error{
                    
                    print("远程获取消息失败:",err)
                    
                    self?.handleMessage(list: list, loadHistory: true)
                }
            }
        }else{
            
            self.handleMessage(list: list, loadHistory: true)
        }
        
        
    }
    
    func load_newest_message() {
        
        
        first_scroll_bottom = true
        
        //        let q = dispatch_queue_global_t(label: "createBrowerQueue")
        //
        //        q.sync() {
        //            originalImageArray.removeAll()
        //            originalImageUUIDArray.removeAll()
        //        }
        
        
        
        
        if let list = NIMSDK.shared().conversationManager.messages(in: session, message: nil, limit: self.pageSize){
            
            //            for item in list{
            //                print("每条消息的时间---",item.timestamp)
            //            }
            
            if list.count < self.pageSize{
                
                let option = NIMHistoryMessageSearchOption()
                
                option.limit = UInt(self.pageSize)
                
                if let first = list.first{
                    
                    option.endTime = first.timestamp
                    option.currentMessage = first
                }else{
                    option.endTime = 0
                }
                
                option.sync = true
                
                NIMSDK.shared().conversationManager.fetchMessageHistory(self.session, option: option) {[weak self] (error, historyList) in
                    
                    if let rList = historyList{
                        
                        //                            for item in rList{
                        //                                print("historyList 每条消息的时间---",item.timestamp)
                        //                            }
                        
                        let dataList = rList.reversed() + list
                        
                        self?.handleMessage(list: dataList)
                        
                    }else{
                        
                        self?.handleMessage(list: list)
                    }
                    
                    if let err = error{
                        
                        print("远程获取消息失败:",err)
                        
                        self?.handleMessage(list: list)
                    }
                }
            }else{
                self.handleMessage(list: list)
            }
            
        }
    }
    
    
    let support_types = [NIMMessageType.text,NIMMessageType.image,NIMMessageType.video,NIMMessageType.audio,NIMMessageType.custom]
    
    private var oldestMessageId = 0
    
    func handleMessage(list:[NIMMessage],loadHistory:Bool = false){
        
        //        第一次的数据
        if loadHistory == false{
            
            ST_BTGlobalDataCenter.shared.enter_private_chat_event(sessionId: self.sessionID, source: self.source, isFirst: list.count < 1)
            
            ///  伴心-3.2.8-iOS-男性用户取消“辅助搭讪”功能
            if list.count < 1 && ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .female{
                
                let vc = ST_QuickMessageViewController()
                vc.onSendTextMessage = { [weak self] text in
                    self?.send_text_message(text: text)
                }
                vc.onSendVoiceMessage = { [weak self] (path, duration) in
                    self?.send_voice_message(path: path, duration: duration)
                }
                GlobalPresent(toController: vc)
                
            }
            
            
        }
        
        
        if list.count == 0 {
            if loadHistory{
                main_thread_execute {
                    self.tableView.mj_header?.endRefreshing()
                }
            }else{
                main_thread_execute {
                    self.display_chat_tips = false
                }
            }
            return
        }
        
        back_thread_execute {
            
            var oldMessages = self.data
            
            for item in list.reversed(){
                
                if !self.support_types.contains(item.messageType){
                    continue
                }
                
                if let model = ST_DTChatMessage.analysis(message: item){
                    
                    oldMessages.insert(model, at: 0)
                    
                    if let nextModel = oldMessages[safe:1] {
                        
                        let need = self.need_add_overtime_gap(time1: Double(nextModel.messageTime), time2: Double(model.messageTime))
                        
                        if need  {
                            
                            let timeModel = ST_DTChatMessage()
                            
                            timeModel.cellStyle = .timeinterval
                            
                            timeModel.timeintervalStr = Double(nextModel.messageTime).b_t_global_date_string()
                            
                            timeModel.figureFrame()
                            
                            oldMessages.insert(timeModel, at: 1)
                        }
                    }
                    
                    //                    let q = dispatch_queue_global_t(label: "createBrowerQueue")
                    //
                    //                    q.sync() {
                    //                        self.createOriginalImages(model: model,insert:true)
                    //                    }
                }
                
            }
            
            main_thread_execute {
                
                self.data = oldMessages
                
                if let firstItem = self.data.first{
                    
                    if let msgId = firstItem.uuid.int{
                        self.oldestMessageId = msgId
                    }
                }
                
                for item in self.data{
                    
                    if item.direction == .receive{
                        
                        BINP.update_friend_avatar(id: item.chatID, url: item.portraitUri)
                        
                        break
                    }
                }
                
                
                if loadHistory{
                    
                    self.tableView.mj_header?.endRefreshing()
                    
                    self.tableView.reloadData()
                    if self.data.count > 0{
                        self.tips_label.isHidden = true
                    }
                }else{
                    
                    //                   数据大于0  并且没有我发的
                    if  self.data.count > 0 && self.data.contains(where: {$0.direction == .send}) == false{
                        
                        self.display_chat_tips = true
                    }
                    
                    
                    
                    
                    self.tableView.reloadData()
                    if self.data.count > 0{
                        self.tips_label.isHidden = true
                    }
                    self.d_tscroll_table_view_to_bottom()
                }
                //                self.settingUnreadCount()
                
            }
        }
        
        
        
    }
    
    //    MARK: - Tools Method
    func d_tscroll_table_view_to_bottom(){
        
        self.perform(#selector(ST_PrivateChatViewController.scroll_to_bottom_indefault_model), with: nil, afterDelay: 0, inModes: [RunLoop.Mode.default])
        
    }
    
    @objc func scroll_to_bottom_indefault_model(){
        
        if self.data.count < 1 {
            return
        }
        
        self.tableView.scrollToRow(at: d_t_last_index_path(), at: UITableView.ScrollPosition.top, animated: !first_scroll_bottom)
        
        first_scroll_bottom = false
    }
    
    func d_t_last_index_path()->IndexPath{
        
        return IndexPath.init(row: self.data.count-1, section: 0)
    }
    
    func need_add_overtime_gap(time1:Double,time2:Double)->Bool{
        
        let difMinutes = ((time1 - time2)/60).abs
        
        return difMinutes > 2
    }
    
    func modify_original_images_id(oldId:String,newId:String)  {
        
        //        guard let idx = originalImageUUIDArray.firstIndex(of: oldId) else { return  }
        //
        //        originalImageUUIDArray[idx] = newId
        
        
        //        print("ID:",oldId," 修改为:",newId)
    }
    /*
     func createOriginalImages(model:ST_DTChatMessage,insert:Bool = false){
     
     var photo:ST_SKPhoto!
     
     //        print("需要添加的UUID:",model.uuid)
     
     if model.cellStyle == .Image{
     
     
     if let localPath = model.imageLocalURL,localPath != ""{
     
     if let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: localPath)),let image = UIImage.init(data: data){
     
     photo = ST_SKPhoto.init(image: image)
     
     }
     }
     
     if photo == nil {
     
     if let remoteUrl = model.imageRemoteUrl{
     photo = ST_SKPhoto.init(url: remoteUrl)
     }
     }
     if photo == nil {
     photo = ST_SKPhoto.photoWithImage(UIImage())
     }
     
     if insert{
     originalImageArray.insert(photo, at: 0)
     
     originalImageUUIDArray.insert(model.uuid, at: 0)
     
     }else{
     originalImageArray.append(photo)
     
     originalImageUUIDArray.append(model.uuid)
     }
     }
     
     
     //        else  if model.cellStyle == .gif{
     //
     //            if let fImage = model.gifImg{
     //
     //                let photo = ST_SKPhoto.photoWithImage(fImage)
     //                originalImageArray.append(photo)
     //                originalImageUUIDArray.append(model.uuid)
     //
     //            }else{
     //                let photo = ST_SKPhoto.photoWithImageURL(model.gifUrl)
     //                originalImageArray.append(photo)
     //                originalImageUUIDArray.append(model.uuid)
     //            }
     //
     //        }
     
     
     }
     */
    //    MARK: - Update Local Ext Status
    
    @objc func update_local_msg_ext_handle(notification:Notification){
        
        
        
        let data = JSON(notification.userInfo ?? "")
        
        
        
        //        if data["ext"].dictionaryValue.keys.contains("passedCheck") == false{
        //            return
        //        }
        
        print("Bug--9--","收到通知啦")
        
        let ids = data["msgIdSet"].stringValue
        
        let idArray = ids.split(separator: ",").map({ String($0) })
        
        //        播放动效礼物
        var playSVGUrl:URL?
        
        
        var updateIndexSet = [IndexPath]()
        
        var repliedUpdateSet = Set<String>()
        
        for (idx,item) in self.data.enumerated(){
            
            if idArray.count < 1{
                
                if item.tail.status == .willIncome{
                    
                    if let replied = data["ext"]["replied"].bool,replied == true{
                        
                        item.tail = ST_ChatMessageTailControlModel.init(income: item.tail.income, sendDate: item.tail.date, replied: true)
                        
                        repliedUpdateSet.update(with: item.uuid)
                        
                        updateIndexSet.append(IndexPath(row: idx, section: 0))
                    }
                    
                    if let url = item.goods?.svgaUrl?.url{
                        playSVGUrl = url
                    }
                    
                }
                
                
                
                
            }else if idArray.contains(item.uuid) {
                
                item.updateFrom(locExt: data["ext"])
                
                updateIndexSet.append(IndexPath(row: idx, section: 0))
            }
        }
        
        if repliedUpdateSet.count > 0{
            
            let oldSet = Set(Defaults[.repliedGoodsSet])
            
            let unionSet = oldSet.union(repliedUpdateSet)
            
            Defaults[.repliedGoodsSet] = Array(unionSet)
            
            Defaults.synchronize()
        }
        
        
        
        if updateIndexSet.count > 0 {
            
            print("Bug--9--","找到这\(updateIndexSet.count)条消息")
            
            self.tableView.reloadRows(at: updateIndexSet, with: UITableView.RowAnimation.none)
            
        }else{
            print("Bug--9--","没找到")
        }
        
        
        if let svgUrl = playSVGUrl?.absoluteString,svgUrl.count > 1{
            
            ST_GiftAnimationViewController.browserGift(imageUrl: "", svgaUrl: svgUrl)
            
        }
        
    }
    
    //    MARK: - Append Message
    func modify_red_packet_status(redpacketId:String,status:ST_DTChatRedPacketStatus)  {
        
        main_thread_execute {
            
            
            let findIndex = self.data.firstIndex { (msg) -> Bool in
                return msg.customAttachment255?.redPacketId == redpacketId
            }
            
            if let idx = findIndex?.uInt{
                
                self.data[Int(idx)].redPacketStatus = status
                
                let findCell = self.tableView.visibleCells.first { (cell) -> Bool in
                    return (cell as? ST_DTChatRepacketCell)?.message.customAttachment255?.redPacketId == redpacketId
                }
                
                if let findIcell = findCell,let indexPath = self.tableView.indexPath(for: findIcell){
                    
                    self.tableView.reloadRows(at: [indexPath], with: UITableView.RowAnimation.none)
                }
            }
        }
        
        
        
    }
    
    
    func append_model(_ model:ST_DTChatMessage,receive:Bool = false){
        
        
        /// 女生 发送消息刷新亲密度
        if ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .female && !receive{
            
            main_thread_execute(afterDelay: 1.5) {
                self.pull_intimacy()
            }
        }
        //        男生收到消息刷新
        else if ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .male && receive{
            
            main_thread_execute(afterDelay: 1.5) {
                self.pull_intimacy()
            }
        }
        
        
        
        
        if model.customAttachment255?.type == 1{
            
            modify_red_packet_status(redpacketId: model.customAttachment255?.redPacketId ?? "", status: ST_DTChatRedPacketStatus.received)
        }
        
        if !receive{
            
            back_thread_execute {
                
                if model.goods != nil{
                    self.plus_one_time(requirePost: true)
                }else{
                    self.plus_one_time()
                }
                
                
                let existSend = self.data.contains(where: ({$0.direction == .send}))
                
                
                ST_BTGlobalDataCenter.shared.send_chat_message_event(sessionId: self.sessionID, isFirst: self.data.count < 1, isFirstSend: existSend)
                
            }
        }
        
        
        //        let br = dispatch_queue_global_t(label: "createBrowerQueue")
        //
        //        br.sync() {
        //
        //            self.createOriginalImages(model: model)
        //
        //        }
        
        /*
         if receive == false && send_talk_o_k == false{
         
         
         var param = ["target_accid":model.chatID] as [String:Any]
         
         if let m = self.matched_header_model{
         
         let msgStr = m.match_message.joined(separator: ";")
         
         param.updateValue(msgStr, forKey: "match_message")
         
         param.updateValue(m.match_rate, forKey: "match_rate")
         
         }
         if let source = self.other_chat_source{
         param.updateValue(source, forKey: "source")
         }
         
         
         JVrequest(PH.startTalkApi,parameters:param ,success: { (json) in
         self.send_talk_o_k = true
         print("开启会话:",model.chatID)
         }) { (code, error) in
         print("开启会话:",model.chatID,"---错误")
         }
         }
         */
        
        main_thread_execute {
            
            //发送一条消息后
            if !receive{
                self.tips_label.isHidden = true
            }
            
            
            if receive && self.read_all_msg{
                NIMSDK.shared().conversationManager.markAllMessagesRead(in: NIMSession.init(self.sessionID, type: NIMSessionType.P2P))
            }
            
            
            let current = Date().timeIntervalSince1970
            
            var insertIndexPaths = [IndexPath]()
            
            var lastMsgTime:Double?
            
            
            let lastModel = self.data.last(where: { (msg) -> Bool in
                msg.cellStyle != .timeinterval
            })
            
            if let lastItem = lastModel{
                
                lastMsgTime = Double(lastItem.messageTime)
                
            }
            
            if let last = lastMsgTime{
                
                let need = self.need_add_overtime_gap(time1: current, time2: last)
                
                if need{
                    
                    let timeModel = ST_DTChatMessage()
                    
                    timeModel.cellStyle = .timeinterval
                    
                    timeModel.timeintervalStr = current.b_t_global_date_string()
                    
                    timeModel.figureFrame()
                    
                    self.data.append(timeModel)
                    
                    let insertIndexPath =  IndexPath.init(row: self.data.count - 1, section: 0)
                    
                    insertIndexPaths.append(insertIndexPath)
                }
            }
            
            
            
            self.data.append(model)
            
            let insertIndexPath =  IndexPath.init(row: self.data.count - 1, section: 0)
            
            insertIndexPaths.append(insertIndexPath)
            
            self.tableView.insertRows(at: insertIndexPaths, with: UITableView.RowAnimation.bottom)
            
            
            main_thread_execute(afterDelay: 0.35, block: {
                self.d_tscroll_table_view_to_bottom()
            })
            
        }
        
    }
    
    
    
    func plus_one_time(requirePost:Bool = false){
        
        let key = Defaults[.currentUserID] + self.sessionID
        
        let old = CHAT_TIMES_MAP[key] ?? 0
        
        let newValue = old + 1
        
        print("重点来了111---：",newValue)
        
        CHAT_TIMES_MAP.updateValue(newValue, forKey: key)
        
        //        送礼 就直接调用接口
        
        if requirePost{
            
            back_thread_execute(afterDelay: 1) {
                self.fetch_current_level(key: key)
            }
            
        }else if newValue%7 == 0 {
            self.fetch_current_level(key: key)
        }
    }
    
    
    fileprivate func fetch_current_level(key:String){
        
        
        JVrequest(PH.fetchTalkIntimacyApi,parameters: ["target_accid":self.sessionID], success: { (json) in
            
            main_thread_execute {
                
                print("重点来了：",json)
                
                guard let currUrl = json["data"]["intimacy_image"].string else{
                    return
                }
                
                let realm = try! Realm()
                
                if let first = realm.objects(ST_BTChatSessioninfo.self).filter(NSPredicate.init(format: "chatSession == %@", key)).first{
                    
                    if first.shipURL != currUrl{
                        self.display_sweet_ship(key: key, name: json["data"]["name"].stringValue, url: currUrl)
                    }
                }else{
                    self.display_sweet_ship(key: key, name: json["data"]["name"].stringValue, url: currUrl)
                }
                
            }
            
            self.lock_media_talk = !json["data"]["can_point_talk"].boolValue
            
        }) { (cod, err) in
            
            print("重点来了 err:",err)
            
        }
        
    }
    
    
    fileprivate func display_sweet_ship(key:String,name:String,url:String){
        
        //        发送对方微信
        if let unlockName = self.her_unlock_wechat_level_string,let wechat = self.her_wechat, name.contains(unlockName){
            
            ST_DTChatFeed.shared.sendSimulateWechatNumberMessage(sessionId: self.sessionID, anotherWechat: wechat)
            
            ST_DTChatMessageSendHander.shared.setObserver(sessionId: self.sessionID, send_requre_coin: 0, delegate: self)
            
            
        }
        
        self.member_title_view.refresh_ship_sign(url: url)
        ///[ST_ConversationAdapter todo] 更新友谊图标
        //        ST_ConversationAdapter.shared.refreshShip(url: url, session: self.sessionID)
        
        let animateVC = ST_UnlockSweetShipViewController()
        
        animateVC.overCurrentContext = true
        
        animateVC.over_current_context_alpha = "0.4"
        
        animateVC.url = url
        
        animateVC.name = name
        
        GlobalPresent(toController: animateVC, animated: false)
        
        let chatSession = ST_BTChatSessioninfo()
        chatSession.chatSession = key
        chatSession.shipURL = url
        
        let realm = try! Realm()
        
        try! realm.write {
            realm.add(chatSession, update: Realm.UpdatePolicy.all)
        }
        
    }
    
    
    
    // MARK: - properties
    
    fileprivate var another_gender:Int?
    
    var hidden_more_tool_btn = false
    
    
    override var hidden_right_btn: Bool {
        set {
            super.hidden_right_btn = newValue
        }
        get {
            return SYSTEM_SESSION_SET.contains(self.sessionID) || hidden_more_tool_btn
        }
    }
    
    //    chat session ID
    var sessionID = ""{
        didSet{
            
            ST_DTChatMessageSendHander.shared.setObserver(sessionId: sessionID, delegate: self)
            
        }
    }
    
    /**
     统计使用
     "个人主页｜特质匹配｜闪聊匹配
     ｜丘比特匹配｜个人特质页｜消息-闪聊｜聊天列表"
     */
    var source = ""
    
    fileprivate var is_puppet = false
    
    fileprivate var send_second = 3
    
    fileprivate var chat_user_face_status = 0
    
    var canChat = false
    
    /// 昵称或者备注
    fileprivate var chatTitle = ""{
        didSet{
            self.member_title_view.update_user_title(str: chatTitle)
        }
    }
    
    private lazy var session:NIMSession = {
        return NIMSession.init(self.sessionID, type: NIMSessionType.P2P)
    }()
    
    /*
     lazy var sendHander:ST_DTChatMessageSendHander = {
     
     let obj = ST_DTChatMessageSendHander.init(sessionId: self.sessionID, delegate: self)
     
     
     //        init(sessionId: self.sessionID, table: self.tableView, chatController: self)
     
     obj.modifyIdClosure = {[weak self] old,new in
     self?.modify_original_images_id(oldId: old, newId: new)
     }
     if let chatSource = self.other_chat_source{
     obj.source = chatSource
     }
     
     
     return obj
     }()
     */
    
    
    
    lazy var record_audio_sign_view:UIImageView = {
        let control = UIImageView()
        //        control.image = ST_ImageUtils.imageName("n_私信_bj_发送语音")
        control.isHidden = true
        return control
    }()
    
    lazy var speak_power_view:UIImageView = {
        let control = UIImageView()
        return control
    }()
    
    lazy var tableView:UITableView = {
        let table = UITableView()
        
        table.delegate = self
        table.dataSource = self
        //        if #available(iOS 11.0, *) {
        //            table.estimatedRowHeight = 50
        //            table.rowHeight = UITableViewAutomaticDimension
        //        }
        //
        //        if #available(iOS 11.0, *) {
        //            table.contentInsetAdjustmentBehavior = .never
        //        } else {
        //            automaticallyAdjustsScrollViewInsets = false
        //        }
        
        table.backgroundColor = Color.white
        table.separatorStyle = .none
        table.showsVerticalScrollIndicator = false
        
        
        table.register(cellWithClass: ST_PrivateChatTipsCell.self)
        
        table.register(cellWithClass: DTChatTextLeftCell.self)
        table.register(cellWithClass: DTChatTextRightCell.self)
        
        
        table.register(cellWithClass: ST_DTImageChatLeftCell.self)
        table.register(cellWithClass: ST_DTImageChatRightCell.self)
        
        
        table.register(cellWithClass: UITableViewCell.self)
        
        
        table.register(cellWithClass: ST_DTVoiceChatLeftCell.self)
        table.register(cellWithClass: ST_DTVoiceChatRightCell.self)
        
        
        table.register(cellWithClass: ST_DTVideoLeftCell.self)
        table.register(cellWithClass: ST_DTVideoRightCell.self)
        
        table.register(cellWithClass: ST_DTChatEmojiLeftCell.self)
        table.register(cellWithClass: DTChatEmojiRightCell.self)
        
        table.register(cellWithClass: ST_DTChatIncomeGiftLeftCell.self)
        table.register(cellWithClass: ST_DTChatIncomeGiftRightCell.self)
        
        
        table.register(cellWithClass: ST_DTSnapChatLeftCell.self)
        table.register(cellWithClass: ST_DTSnapChatRightCell.self)
        
        
        table.register(cellWithClass: ST_DTChatRepacketLeftCell.self)
        table.register(cellWithClass: ST_DTChatRepacketRightCell.self)
        table.register(cellWithClass: ST_DTChatReceivedRepacketCell.self)
        
        
        
        
        table.register(cellWithClass: ST_ChatTimeintervalCell.self)
        table.register(cellWithClass: ST_RechargeTipsCell.self)
        table.register(cellWithClass: ST_LittleLuckTipsCell.self)
        
        
        table.register(cellWithClass: ST_DTMaskChatCell.self)
        
        
        //        礼物
        table.register(cellWithClass: ST_DTChatGoodsLeftCell.self)
        table.register(cellWithClass: ST_DTChatGoodsRightCell.self)
        
        
        table.register(cellWithClass: ST_CallRecordLeftCell.self)
        table.register(cellWithClass: ST_CallRecordRightCell.self)
        
        
        table.register(cellWithClass: ST_DTInviteVoiceGroupLeftCell.self)
        table.register(cellWithClass: ST_DTInviteVoiceGroupRightCell.self)
        
        
        table.register(cellWithClass: ST_DTFemaleInviteChatLeftCell.self)
        table.register(cellWithClass: ST_DTFemaleInviteChatRightCell.self)
        
        
        table.mj_header = MJRefreshNormalHeader.init(refreshingBlock: {[weak self] in
            self?.load_history_message()
        })
        
        table.contentInset = UIEdgeInsets.init(top: 0, left: 0, bottom: 10, right: 0)
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(table_tapped))
        table.backgroundView = UIView()
        table.backgroundView?.addGestureRecognizer(tap)
        table.showsVerticalScrollIndicator = false
        table.showsHorizontalScrollIndicator = false
        return table
    }()
    
    
    fileprivate lazy var banBtn:ST_VerticalButton = {
        
        let control = ST_VerticalButton()
        
        if ST_BTUserInfoManager.shared.current_account_info?.userinfo?.sex == .male || Defaults[.isPanda] {
            control.alpha = 1
        }else{
            control.alpha = 0
        }
        
        
        control.image_view_edges = UIEdgeInsets.init(top: 0, left: 0, bottom: 14, right: 0)
        
        control.setImage(ST_ImageUtils.imageName("屏蔽_icon")!, for: UIControl.State.normal)
        
        let attrString = NSMutableAttributedString(string: "拉黑")
        
        let attr: [NSAttributedString.Key : Any] = [.font: UIFont.systemFont(ofSize: 10),.foregroundColor: UIColor(red: 0.67, green: 0.71, blue: 0.75, alpha: 1)]
        
        attrString.addAttributes(attr, range: NSRange(location: 0, length: attrString.length))
        
        control.setTitleForAllStates(attrString)
        
        control.addTarget(self, action: #selector(ban_click_handle), for: UIControl.Event.touchUpInside)
        
        return control
    }()
    
    fileprivate var keyboard_height = 0.cgFloat
    
    lazy var inputBar:ST_BTChatInputBar = {
        
        let control = ST_BTChatInputBar.init(frame: .zero, is_chat_to_assistant: sessionID == DIALOGUE_ASSISTANT_SESSION_ID)
        control.input_placeholder_text = "请礼貌聊天..."
        control.vc = self
        return control
    }()
    
    
    fileprivate lazy var matched_header_view:ST_ChatMatchedView = {
        let control = ST_ChatMatchedView()
        control.sessionId = self.sessionID
        return control
    }()
    
    
    fileprivate lazy var headerView:ST_ChatUserHeader = {
        let control = ST_ChatUserHeader()
        control.sessionId = self.sessionID
        return control
    }()
    
    fileprivate lazy var tips_header_view:ChatTipsForMeView = {
        let control = ChatTipsForMeView()
        return control
    }()
    
    
    fileprivate lazy var normal_first_accost_string:NSAttributedString = {
        
        let attrString = NSMutableAttributedString(string: "第一条消息请一定要认真有礼貌地传达你的喜欢哟~\n如果使用不当词语，对方很有可能会将你拉黑！发送其他社交平台账号也是不允许的")
        
        let paragh = NSMutableParagraphStyle()
        
        paragh.lineSpacing = 3
        
        let attr: [NSAttributedString.Key : Any] = [.font: UIFont.systemFont(ofSize: 14),.foregroundColor: UIColor(red: 0.67, green: 0.71, blue: 0.75, alpha: 1),.paragraphStyle:paragh]
        
        attrString.addAttributes(attr, range: NSRange(location: 0, length: attrString.length))
        
        return attrString
    }()
    
    fileprivate lazy var pay_tips_first_accost_string:NSAttributedString = {
        
        
        let normalAttr:[Attribute] = [.font( UIFont.systemFont(ofSize: 14)),.textColor(UIColor(red: 0.67, green: 0.71, blue: 0.75, alpha: 1))]
        
        let yellowAttr: [Attribute] = [.font(UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.medium)),.textColor( UIColor.init(hex: 0xFEC207)!)]
        
        let attrString = "为了提高用户质量，将交友机会留给诚意用户，发送消息会消耗".withAttributes(normalAttr)
        let str0 = "甜心币".withAttributes(yellowAttr)
        let str1 = "，当你和对方的亲密度达到了".withAttributes(normalAttr)
        
        let keyStr = self.her_unlock_wechat_level_string ?? "  "
        
        let str2 = keyStr.withAttributes(yellowAttr)
        let str3 = "时开启畅聊，如果对方设置了".withAttributes(normalAttr)
        let str4 = "微信号".withAttributes(yellowAttr)
        let str5 = "，亲密度达到的同时也会自动解锁".withAttributes(normalAttr)
        
        attrString.append(str0)
        attrString.append(str1)
        attrString.append(str2)
        attrString.append(str3)
        attrString.append(str4)
        attrString.append(str5)
        
        attrString.addAttributes([NSAttributedString.Key.paragraphStyle:NSParagraphStyle.create_line_spacing_paragraph_style(lineSpacing: 2)], range: NSRange(location: 0, length: attrString.length))
        
        return attrString
    }()
    
    fileprivate lazy var tips_label:UILabel = {
        
        let control = UILabel()
        
        control.numberOfLines = 0
        
        control.isHidden = true
        
        
        
        return control
    }()
    
    
    fileprivate lazy var top_tips_view:ST_ChatTopToastVIew = {
        let control = ST_ChatTopToastVIew()
        control.alpha = 0
        control.transform = CGAffineTransform(translationX: 0, y: -15)
        return control
    }()
    
    fileprivate var guardURL:URL?{
        didSet{
            refresh_guard()
        }
    }
    
    fileprivate lazy var next_intimacy_percentage_view:ST_CirclePercentageIntimacyView = {
        let v = ST_CirclePercentageIntimacyView()
        return v
    }()
    
    
    var intimacyImage:String?
    
    //    MARK: - Play Audio
    var last_play_audio_cell:ST_DTVoiceChatCell?
    
    var last_play_audio_message:ST_DTChatMessage?
    
    lazy var audioPlayer:ST_BTAudioPlayer = {
        
        let player = ST_BTAudioPlayer.sharedInstance()!
        
        player.playComplete = { [weak self] in
            
            if let lastCell = self?.last_play_audio_cell{
                
                if self?.tableView.visibleCells.contains(lastCell) ?? false{
                    self?.last_play_audio_cell?.stop_play_animation()
                }
            }
            
            if let lastMessae = self?.last_play_audio_message{
                lastMessae.audioPlaying = false
            }
        }
        
        return player
    }()
    
    //    MARK: - data Properties
    var data = [ST_DTChatMessage]()
    
    
    //    MARK: - Tool bar
    var DTtoolBar:ST_DTChatToolBar?
    
    //    MARK: - Event
    func require_detect_handle(){
        
        if self.chat_user_face_status == 3{
            
            self.toast(text: "对方已经完成真人认证咯")
            
            return
        }
        
        
        JVrequest(PH.inviteFaceApi,parameters: ["target_accid":self.sessionID], success: { (json) in
            
            let goods = ST_BTIMGiftMessageModel()
            
            goods.title = "要求进行真人认证"
            
            goods.type = ST_IMGoodsType.requireDetect
            
            goods.subTitle = "认证后才能继续对话"
            
            self.send_goods_message(goods: goods)
            
        }) { (code, err) in
            
            self.toast(text: err)
        }
        
        
        
        
    }
    
    fileprivate func send_msg_of_receive_red_packet(msg:ST_DTChatMessage){
        
        guard let attach = msg.customAttachment255,msg.direction == .receive else {
            return
        }
        
        if msg.redPacketStatus != .normal{
            
            return
        }
        
        self.show_indeterminate_h_u_d()
        
        JVrequest(PH.receiveRedPacketApi, parameters: ["red_packet_id":attach.redPacketId], queue: nil ,success:{ (json) in
            
            self.hidden_indeterminate_h_u_d()
            
            let realm = try! Realm()
            
            let updateModel = ST_BTRedPacketTemporaryStatusModel()
            updateModel.redPacketId = attach.redPacketId
            updateModel.status = 1
            
            try! realm.write({
                realm.add(updateModel, update: Realm.UpdatePolicy.all)
            })
            
            msg.redPacketStatus = .received
            
            //            self.tableView.reloadData()
            
            
            let vc = ST_ReceivedRedPacketAlertController()
            
            vc.overCurrentContext = true
            
            let number = msg.customAttachment255?.redPacketCoinNum ?? 0
            
            vc.bind_data(nickName: msg.userName, avatar: msg.portraitUri, coinNumber: number.float/10.0, unitStr: "\(Defaults[.PandaStr])", statusString: "已存入\(Defaults[.PandaLinkStr])", redPacketStr: msg.customAttachment255?.redPacketTxt ?? "")
            
            GlobalPresent(toController: vc, animated: false)
            
            let receiveAttach = ST_Custom255AttachmentModel()
            
            receiveAttach.type = 1
            receiveAttach.redPacketId = attach.redPacketId
            receiveAttach.redPacketCoinNum = attach.redPacketCoinNum
            receiveAttach.redPacketIncome = attach.redPacketIncome
            receiveAttach.redPacketTxt = attach.redPacketTxt
            
            self.sendRedPacketOfReceivedMessage(attach: receiveAttach)
            
        }, failure: { (code, err) in
            
            self.toast(text: err)
        })
        
    }
    
    func receive_red_packet_action(msg:ST_DTChatMessage){
        
        let number = msg.customAttachment255?.redPacketCoinNum ?? 0
        
        if msg.direction == .receive{
            
            switch msg.redPacketStatus {
            case .normal:
                send_msg_of_receive_red_packet(msg: msg)
            default:
                
                let vc = ST_ReceivedRedPacketAlertController()
                
                vc.overCurrentContext = true
                
                let str = msg.redPacketStatus == .expire ? "该红包已过期" : "该红包已领取"
                
                
                
                
                vc.bind_data(nickName: msg.userName, avatar: msg.portraitUri, coinNumber: number.float/10.0, unitStr: "\(Defaults[.PandaStr])", statusString: str, redPacketStr: msg.customAttachment255?.redPacketTxt ?? "")
                
                GlobalPresent(toController: vc, animated: false)
            }
        }else{
            
            guard let userinfo = ST_BTUserInfoManager.shared.current_account_info?.userinfo else { return  }
            
            let vc = ST_ReceivedRedPacketAlertController()
            
            vc.overCurrentContext = true
            
            var str = ""
            
            switch msg.redPacketStatus {
            case .expire:
                str = "该红包已过期"
            case .received:
                str = "该红包已领取"
            default:
                str = "该红包待领取"
            }
            
            vc.bind_data(nickName: userinfo.nickname, avatar: userinfo.avatar, coinNumber: number.float, unitStr: "个", statusString: str, redPacketStr: msg.customAttachment255?.redPacketTxt ?? "")
            
            GlobalPresent(toController: vc, animated: false)
            
            
        }
        
        
        
        
        
        
        
    }
    
    private func start_video_chat(){
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else {
            return
        }
        
        if user.sex == .female{
            
            if !ST_PrivateInviteChatTimesLog.canInvite(type: 2, targetId: sessionID){
                
                self.toast(text: "邀请次数限制啦~，明天再来吧")
                
                return
                
            }
            
            self.sendFemaleInviteMessage(type: 2)
            
            return
        }
        
        
        ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
            
            ST_MediaChatDispatcher.shared.request_video_permission_with_execute {
                
                ST_MediaChatDispatcher.shared.inviteChat(sessionId: self.sessionID, isVideo: true)
            }
        }
        
    }
    
    private func start_voice_chat(){
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else {
            return
        }
        
        if user.sex == .female{
            
            if !ST_PrivateInviteChatTimesLog.canInvite(type: 1, targetId: sessionID){
                
                self.toast(text: "邀请次数限制啦~，明天再来吧")
                
                return
                
            }
            self.sendFemaleInviteMessage(type: 1)
            
            return
        }
        
        ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
            
            ST_MediaChatDispatcher.shared.inviteChat(sessionId: self.sessionID, isVideo: false)
        }
        
    }
    
    ///发起视频语音通话
    func media_talk_options_handle(){
        
        
        guard let gender = self.another_gender,let anotherSex = ST_SEX.init(rawValue: gender) else {
            
            self.toast(text: "网络出了点问题，请稍后")
            
            return
        }
        //        影响
        //        if ST_MediaChatDispatcher.shared.status == .matching{
        //
        //            self.toast(text: "关闭了匹配中才能私聊")
        //
        //            return
        //        }
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else{
            return
        }
        
        //        男和女才能聊天
        if anotherSex == user.sex,let str = SCComponets.rich_text_storage_component.json["limitations"]["cot"].string,str.count > 2{
            
            self.toast(text: str)
            
            return
        }
        
        
        
        if user.sex == .female && FACE_AVATAE_STATE != 3{
            
            
            ToastDetectFaceTips(vcCreater: nil)
            
            
            return
            
        }
        
        
        
        let vc = ST_BTSheetActionController.init(title: nil, message: nil)
        
        let attr: [NSAttributedString.Key : Any] = [.font: UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.medium),.foregroundColor: UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)]
        
        let str1 = NSMutableAttributedString.init(string: "语音通话")
        
        str1.addAttributes(attr, range: NSRange(location: 0, length: str1.length))
        
        vc.addAction(ST_BTAlertAction.init(title: str1, handler: {[weak self] (action) in
            
            self?.start_voice_chat()
            
            
        }))
        
        
        let str2 = NSMutableAttributedString.init(string: "视频通话")
        
        str2.addAttributes(attr, range: NSRange(location: 0, length: str2.length))
        
        vc.addAction(ST_BTAlertAction.init(title: str2, handler: {[weak self] (action) in
            
            self?.start_video_chat()
            
            
        }))
        
        vc.show()
        
    }
    
    func show_goods_handle(){
        
        let giftAlert = ST_GiftViewController()
        
        giftAlert.overCurrentContext = true
        
        giftAlert.over_current_context_alpha = "0.4"
        
        giftAlert.userId = self.sessionID
        
        if let user = BINP.fetch_nickname_with_avatar(userId: self.sessionID){
            
            giftAlert.avatar = user.avatar
        }
        
        
        GlobalPresent(toController: giftAlert)
        
    }
    
    @objc func table_tapped(){
        
        dismissMessageToolBar()
        
        
    }
    
    func push_user_controller_handle(){
        
        let vc = ST_PairsCenterViewController()
        
        
        vc.accid = self.sessionID
        
        let nav = PairsCenterInteractiveNavigationController.init(rootViewController: vc)
        
        nav.overCurrentContext = true
        
        GlobalPresent(toController: nav)
        
    }
    
    
    
    @objc func ban_click_handle(){
        
        let attrString = NSMutableAttributedString(string: "拉黑对方")
        
        let attr: [NSAttributedString.Key : Any] = [.font: UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.medium),.foregroundColor: UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)]
        attrString.addAttributes(attr, range: NSRange(location: 0, length: attrString.length))
        
        let attrString1 = NSMutableAttributedString(string: "拉黑后对方将不会看到你的任何资料\n也不能再给你发消息")
        
        let paragh = NSMutableParagraphStyle()
        paragh.alignment = .center
        
        let attr1: [NSAttributedString.Key : Any] = [.font: UIFont.systemFont(ofSize: 14),.foregroundColor: UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1),.paragraphStyle:paragh]
        
        attrString1.addAttributes(attr1, range: NSRange(location: 0, length: attrString1.length))
        
        
        let alert = BTVerticalAlertViewController.init(title: attrString, message: attrString1, imageName: "私聊_屏蔽_icon", confirmText: "我要拉黑", cancelText: "再想想")
        
        alert.overCurrentContext = true
        
        alert.over_current_context_alpha = "0.4"
        
        alert.root_view_height = 345
        
        alert.root_view_width = 300
        
        alert.cover_image_size = CGSize.init(width: 100, height: 100)
        
        alert.confirm_closure = { [weak self] in
            
            self?.ban_current_user_handle()
            
        }
        GlobalPresent(toController: alert, animated: false)
        //           GlobalPresent(toController: alert)
        
    }
    
    @objc func ban_current_user_handle(){
        
        
        BAN_SOMEBODY_HANDLE(userId: self.sessionID, close_view: true, hud_controller: self)
        
    }
    
    private func setting_remark_name(){
        
        let vc =  ST_EditInfoTextFieldController()
        
        vc.title = "设置备注昵称"
        
        vc.placeholder = "请输入备注昵称"
        
        vc.maxLength = 14
        
        vc.display_text = chatTitle
        
        vc.update_value_closure = {[weak self] m in
            
            JVrequest(PH.settingRemarkApi,parameters: ["target_accid":self?.sessionID ?? "","remark":m]) { json in
                
                self?.chatTitle = m
                
                BINP.update_friend_remark(id: self?.sessionID ?? "", remark: m)
                
                self?.toast(text: "备注设置成功")
                
            } failure: { code, err in
                
                self?.toast(text: err)
            }
            
            //            factory chimneys discharge smoke into the atmosphere and make it dirty
            
            //            you have to be accompanied by a parent or guardian.
            
            
        }
        
        GlobalPresent(toController: vc)
    }
    
    override func right_click() {
        
        let alert = UIAlertController.init(title: nil, message: nil, preferredStyle: UIAlertController.Style.actionSheet)
        
        alert.addAction(title: "设置备注昵称", style: UIAlertAction.Style.default, isEnabled: true) {[weak self] (action) in
            
            self?.setting_remark_name()
        }
        
        alert.addAction(title: "举报", style: UIAlertAction.Style.default, isEnabled: true) { (action) in
            
            let vc = ST_ReportPersonController()
            vc.userId = self.sessionID
            
            let nav = UINavigationController.create_hiding_bar_navigation_controller(rootViewController: vc)
            GlobalPresent(toController: nav)
            
        }
        
        alert.addAction(title: "查看个人主页", style: UIAlertAction.Style.default, isEnabled: true) { (action) in
            
            self.push_user_controller_handle()
            
        }
        
        
        alert.addAction(title: "解除匹配", style: UIAlertAction.Style.default, isEnabled: true) { (action) in
            
            self.show_indeterminate_h_u_d()
            
            JVrequest(PH.removeMatchApi, parameters: ["target_accid":self.sessionID],success: { (json) in
                
                self.hidden_indeterminate_h_u_d()
                
                ST_ConversationAdapter.shared.delete_recent_conversation(sessionId: self.sessionID)
                
                ST_BTUserInfoManager.shared.refresh_my_sweetheart_list()
                
                
                self.goback_previous_controller()
                
            },failure: { (code, err) in
                
                self.toast(text: err)
            })
        }
        
        alert.addAction(title: "取消", style: UIAlertAction.Style.cancel, isEnabled: true) { (action) in
            
        }
        
        
        GlobalPresent(toController: alert)
    }
}


extension ST_PrivateChatViewController:UITableViewDelegate,UITableViewDataSource{
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let message = self.data[indexPath.row]
        
        let identifier = self.cellIdentifierForMessage(message)
        
        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        
        if let chatCell = cell as? ST_DTChatCell{
            
            chatCell.message = message
            
            chatCell.push_user_centerClosure = {[weak self] in
                
                if self?.hidden_more_tool_btn == true{
                    return
                }
                self?.push_user_controller_handle()
            }
            
            chatCell.icon_supplement_u_r_l = self.guardURL
            
        }
        
        if let intervalCell = cell as? ST_ChatTimeintervalCell{
            
            intervalCell.message = message
            
        }
        
        if let iCell = cell as? ST_PrivateChatTipsCell{
            
            iCell.message = message
            
        }
        if let iCell = cell as? ST_LittleLuckTipsCell{
            
            iCell.message = message
            
            iCell.video_chat_closure = {[weak self] in
                self?.media_talk_options_handle()
            }
            
            //            iCell.voiceChatClosure = {[weak self] in
            //                self?.media_talk_options_handle(type: 1)
            //            }
        }
        
        
        
        if let audioCell = cell as? ST_DTVoiceChatCell{
            
            audioCell.playDelegate = self
            
        }
        
        if let imageCell = cell as? ST_DTImageChatCell{
            
            imageCell.show_full_image_closure = { [weak self] imgCell in
                
                self?.displayOriginalImage(cell: imgCell)
                
            }
        }
        
        if let goodsCell = cell as? ST_DTChatGoodsLeftCell{
            
            goodsCell.present_goods_closure = { [weak self] in
                self?.show_goods_handle()
            }
            
        }
        
        if let goodsCell = cell as? ST_DTChatIncomeGiftLeftCell{
            
            goodsCell.present_goods_closure = { [weak self] in
                self?.show_goods_handle()
            }
            
        }
        
        if let redPacketCell = cell as? ST_DTChatRepacketCell{
            
            redPacketCell.received_red_packet_closure = { [weak self] msg in
                self?.receive_red_packet_action(msg: msg)
            }
            
        }
        
        if let rechargeCell = cell as? ST_RechargeTipsCell{
            //            rechargeCell.send_requre_coin = self.send_requre_coin ?? 0
            rechargeCell.keyString = self.her_unlock_wechat_level_string ?? ""
        }
        
        if let iCell = cell as? ST_DTInviteVoiceGroupCell{
            
            iCell.join_closure = {[weak self] m in
                
                //                ST_BTIMInviteMessageModel
                if ST_BTUserInfoManager.shared.app_chat_status_behavior.value.rawValue != 0{
                    
                    self?.toast(text: "当前不能加入语音房")
                    
                    return
                }
                
                
                self?.show_indeterminate_h_u_d()
                
                
                
            }
            
        }
        
        
        
        if let iCell = cell as? ST_DTFemaleInviteChatLeftCell{
            
            iCell.recall_female_chat_invited = {[weak self] chatType in
                
                if chatType == 1{
                    self?.start_voice_chat()
                }else{
                    self?.start_video_chat()
                }
            }
        }
        
        return cell
    }
    
    
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        
        return self.data[indexPath.row].cellHeight
        
    }
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        
        if self.inputBar.heightStatus == .normal{
            return
        }
        
        self.inputBar.heightStatus = .normal
        self.inputBar.endEditing(true)
        
        self.changeFrame()
        
    }
    
    
    private func cellIdentifierForMessage(_ message:ST_DTChatMessage)->String{
        
        var str = ""
        
        switch message.cellStyle {
        case .Image:
            if message.direction == .receive{
                str = String(describing: ST_DTImageChatLeftCell.self)
            }else{
                str = String(describing: ST_DTImageChatRightCell.self)
            }
        case .voice:
            
            if message.direction == .receive{
                str = String(describing: ST_DTVoiceChatLeftCell.self)
            }else{
                str = String(describing: ST_DTVoiceChatRightCell.self)
            }
            
        case .CustomNewEmoji:
            
            if message.direction == .receive{
                str = String(describing: ST_DTChatEmojiLeftCell.self)
            }else{
                str = String(describing: DTChatEmojiRightCell.self)
            }
            
        case .snapChat:
            
            if message.direction == .receive{
                str = String(describing: ST_DTSnapChatLeftCell.self)
            }else{
                str = String(describing: ST_DTSnapChatRightCell.self)
            }
        case .redPacket:
            
            if message.direction == .receive{
                str = String(describing: ST_DTChatRepacketLeftCell.self)
            }else{
                str = String(describing: ST_DTChatRepacketRightCell.self)
            }
        case .redPacketReceived:
            str = String(describing: ST_DTChatReceivedRepacketCell.self)
            
        case .Text:
            
            if message.direction == .receive{
                str = String(describing: DTChatTextLeftCell.self)
            }else{
                str = String(describing: DTChatTextRightCell.self)
            }
            
        case .Video:
            
            if message.direction == .receive{
                str = String(describing: ST_DTVideoLeftCell.self)
            }else{
                str = String(describing: ST_DTVideoRightCell.self)
            }
            
        case .goodsType:
            
            if message.direction == .receive{
                str = String(describing: ST_DTChatGoodsLeftCell.self)
            }else{
                str = String(describing: ST_DTChatGoodsRightCell.self)
            }
            
        case .likeProp,.incomeGuard,.incomeGift:
            
            if message.direction == .receive{
                str = String(describing: ST_DTChatIncomeGiftLeftCell.self)
            }else{
                str = String(describing: ST_DTChatIncomeGiftRightCell.self)
            }
        case .recharge:
            str = String(describing: ST_RechargeTipsCell.self)
        case .tips:
            str = String(describing: ST_PrivateChatTipsCell.self)
        case .unlockCallTips:
            str = String(describing: ST_LittleLuckTipsCell.self)
        case .callRecord:
            
            if message.direction == .receive{
                str = String(describing: ST_CallRecordLeftCell.self)
            }else{
                str = String(describing: ST_CallRecordRightCell.self)
            }
        case .inviteVoiceGroup:
            if message.direction == .receive{
                str = String(describing: ST_DTInviteVoiceGroupLeftCell.self)
            }else{
                str = String(describing: ST_DTInviteVoiceGroupRightCell.self)
            }
        case .femaleInviteChat:
            if message.direction == .receive{
                str = String(describing: ST_DTFemaleInviteChatLeftCell.self)
            }else{
                str = String(describing: ST_DTFemaleInviteChatRightCell.self)
            }
            //            时间间隙 和 撤回消息 统一 一个Cell
        default:
            str = String(describing: ST_ChatTimeintervalCell.self)
        }
        
        return str
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        self.dismissMessageToolBar()
        
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        super.touchesBegan(touches, with: event)
        
        dismissMessageToolBar()
    }
    
    
    
}



extension ST_PrivateChatViewController{
    
    func key_broad_height_changed(notification:Notification){
        
        if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            
            let keyboardRectangle = keyboardFrame.cgRectValue
            
            let keyboard_height = keyboardRectangle.height
            
            //            if #available(iOS 11.0, *) {
            //                let bottomInset = self.view.safeAreaInsets.bottom
            //                keyboard_height -= bottomInset
            //            }
            //            print("iPhone X 键盘",keyboard_height)
            self.keyboard_height = keyboard_height
            self.inputBar.heightStatus = self.inputBar.input_status_control_btn.isSelected ? .face : .keybroad
            self.changeFrame()
        }
    }
    
    func changeFrame(){
        
        var input_height = ST_BTChatInputBar.input_height
        
        switch self.inputBar.heightStatus {
        case .keybroad,.face:
            
            input_height += self.keyboard_height
        default:
            
            input_height = ST_BTChatInputBar.normal_height
        }
        
        self.inputBar.snp.updateConstraints { (make) in
            make.height.equalTo(input_height)
        }
        //        print("iPhone X 键盘 input_height",input_height)
        let kKeyboardChangeFrameTime = 0.25
        
        UIView.animate(withDuration: kKeyboardChangeFrameTime, animations: {
            self.view.layoutIfNeeded()
        })
        
        d_tscroll_table_view_to_bottom()
        
        dismissMessageToolBar()
        
    }
    
    //    MARK: - Show FUll Image
    func displayOriginalImage(cell:ST_DTChatCell){
        
        
        let imageResourceArray = self.data.filter { (msg) -> Bool in
            return msg.cellStyle == .Image
        }
        
        let photos = imageResourceArray.map { (model) -> ST_SKPhoto in
            
            var photo:ST_SKPhoto?
            
            if let check = model.passedCheck,check == false{
                return ST_SKPhoto()
            }
            
            if let localPath = model.imageLocalURL,localPath != ""{
                
                if let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: localPath)),let image = UIImage.init(data: data){
                    
                    photo = ST_SKPhoto.init(image: image)
                    
                }
            }
            if photo == nil {
                if let remoteUrl = model.imageRemoteUrl{
                    photo = ST_SKPhoto.init(url: remoteUrl)
                }
            }
            if photo == nil {
                photo = ST_SKPhoto.photoWithImage(UIImage())
            }
            
            return photo ?? ST_SKPhoto()
        }
        
        let index = imageResourceArray.firstIndex { (msg) -> Bool in
            return msg.uuid == cell.message.uuid
        }
        
        if let currentIdx = index?.uInt{
            
            ST_ST_ST_SKPhotoBrowserOptions.displayAction = false
            
            let browser = ST_ST_SKPhotoBrowser.init(photos: photos, initialPageIndex: Int(currentIdx))
            
            self.present(browser, animated: true, completion: {})
        }
        
        
    }
    
    
    
    //    MARK: - tool bar
    
    
    
    func long_pressed(cell:ST_DTChatCell){
        
        dismissMessageToolBar()
        
        /*
         if let indexPath = self.tableView.indexPath(for: cell){
         
         var rect = self.tableView.rectForRow(at: indexPath)
         
         rect = self.tableView.convert(rect, to: self.view)
         
         guard let message = cell.message else{
         print("聊天 消息错误")
         return
         }
         
         
         let existRecallStyle : [ST_DTChatCellStyle] = [.Text,.Image,.Video,.gif,.voice,.CustomNewEmoji]
         
         if !existRecallStyle.contains(message.cellStyle){
         return
         }
         
         var contentFrame = message.textBackFrame
         
         if message.cellStyle == .Image || message.cellStyle == .Video || message.cellStyle == .gif {
         
         contentFrame = message.imageFrame
         }
         
         if message.cellStyle == .voice{
         
         contentFrame = message.audioFrame
         }
         
         if message.cellStyle == .CustomNewEmoji{
         return
         }
         
         let offset = contentFrame.maxX - contentFrame.width/2.0
         
         let y = rect.origin.y - ST_DTChatToolBar.back_view_height - ST_DTChatToolBar.triangle_height + 13
         
         let frame = CGRect.init(x: 0, y: y, width: ScreenWidth, height: ST_DTChatToolBar.back_view_height + ST_DTChatToolBar.triangle_height)
         
         let toolbar = ST_DTChatToolBar.init(frame: frame,message:message,longPressedRow: indexPath,triangleViewX: offset)
         
         self.view.addSubview(toolbar)
         
         toolbar.duplicate_text_clousure = {[weak self] in
         self?.dismissMessageToolBar()
         }
         
         toolbar.recall_msg_clousure = {[weak self] id in
         self?.recallMessage(messageId: id)
         }
         
         toolbar.delete_msg_clousure = {[weak self] id in
         self?.deleteMessage(messageId: id)
         }
         
         DTtoolBar = toolbar
         }*/
        
    }
    
    
    
    func recallMessage(messageId:String,isMyOperation:Bool = true){
        
        main_thread_execute {
            
            self.dismissMessageToolBar()
            
            guard let row = self.data.firstIndex(where: { (msg) -> Bool in
                
                msg.uuid == messageId
                
            })else{
                
                print("没有查找到本地 消息")
                
                return
            }
            
            if !isMyOperation{
                //                直接替换当前的消息为撤回
                let chatMsg = ST_DTChatMessage()
                chatMsg.cellStyle = .recall
                chatMsg.recallStr = "对方撤回了一条消息"
                chatMsg.figureFrame()
                self.data[row] = chatMsg
                
                self.tableView.reloadData()
                if self.data.count > 0{
                    self.tips_label.isHidden = true
                }
                return
            }
            
            guard let msg = NIMSDK.shared().conversationManager.messages(in: self.session, messageIds: [messageId])?.first else{
                return
            }
            
            
            NIMSDK.shared().chatManager.revokeMessage(msg, apnsContent: "撤回一条消息", apnsPayload: nil, shouldBeCounted: false) { (error) in
                
                //            }
                //            NIMSDK.shared().chatManager.revokeMessage(msg) { (error) in
                
                if let err = error{
                    
                    ToastHud(text: "撤回错误请稍后再试", view: self.view)
                    
                    print("撤回错误--当前打印:",err)
                    
                }else{
                    
                    //                    直接替换当前的消息为撤回
                    let chatMsg = ST_DTChatMessage()
                    chatMsg.cellStyle = .recall
                    chatMsg.recallStr = "你撤回了一条消息"
                    chatMsg.figureFrame()
                    self.data[row] = chatMsg
                    
                    self.tableView.reloadData()
                    if self.data.count > 0{
                        self.tips_label.isHidden = true
                    }
                }
            }
            self.deleteBrowerImagesUUid(messageId)
        }
    }
    
    
    struct RemoveItem {
        var idx:Int
        var msg:ST_DTChatMessage
    }
    
    func removeItemInTemp(dataList:inout [ST_DTChatMessage] ,uuid:String)->RemoveItem?
    {
        
        var will:Int?
        for (i,item) in dataList.enumerated(){
            if item.uuid == uuid{
                will = i
                break
            }
        }
        
        if let idx = will {
            
            if let msg = dataList[safe:idx]{
                print("BUG Data Count before remove count:",dataList.count)
                dataList.remove(at: idx)
                return RemoveItem.init(idx: idx, msg: msg)
            }
        }
        return nil
    }
    //    测试
    func deleteMessageCopy(messageId:String){
        
        dismissMessageToolBar()
        
        guard let msg = NIMSDK.shared().conversationManager.messages(in: self.session, messageIds: [messageId])?.first else{
            return
        }
        
        guard let row = self.data.firstIndex(where: { (msg) -> Bool in
            
            msg.uuid == messageId
            
        })else{
            
            print("没有查找到本地 消息")
            
            return
        }
        
        NIMSDK.shared().conversationManager.deleteMessage(fromServer: msg, ext: nil) { (error) in
            
            
            if let err = error{
                
                print("删除消息错误:",err)
                
                self.toast(text: "删除消息错误，请稍后再试")
                
            }else{
                
                var temData = self.data
                
                let didRemove = temData.remove(at: row)
                
                self.deleteBrowerImagesUUid(didRemove.uuid)
                
                var timeIntervalIndexPath:IndexPath?
                
                
                if let removeLast = temData[safe:row-1],removeLast.cellStyle == .timeinterval{
                    
                    timeIntervalIndexPath = IndexPath.init(row: temData.count - 1, section: 0)
                    
                    temData.remove(at: row-1)
                }
                
                self.data = temData
                
                var deleteIndexArray = [IndexPath.init(row: row, section: 0)]
                
                if let idx = timeIntervalIndexPath{
                    
                    deleteIndexArray.append(idx)
                }
                
                self.tableView.deleteRows(at: deleteIndexArray, with: UITableView.RowAnimation.bottom)
                
                ST_ConversationAdapter.shared.refresh_all_data()
                
            }
            
        }
        
    }
    
    func deleteMessage(messageId:String){
        
        dismissMessageToolBar()
        
        guard let msg = NIMSDK.shared().conversationManager.messages(in: self.session, messageIds: [messageId])?.first else{
            return
        }
        
        guard let row = self.data.firstIndex(where: { (msg) -> Bool in
            
            msg.uuid == messageId
            
        })else{
            
            print("没有查找到本地 消息")
            
            return
        }
        
        
        if row == 0{
            return
        }
        
        
        NIMSDK.shared().conversationManager.delete(msg)
        
        var temData = self.data
        
        let didRemove = temData.remove(at: row)
        
        self.deleteBrowerImagesUUid(didRemove.uuid)
        
        var timeIntervalIndexPath:IndexPath?
        
        
        if let removeLast = temData[safe:row-1],removeLast.cellStyle == .timeinterval{
            
            timeIntervalIndexPath = IndexPath.init(row: temData.count - 1, section: 0)
            
            temData.remove(at: row-1)
        }
        
        self.data = temData
        
        var deleteIndexArray = [IndexPath.init(row: row, section: 0)]
        
        if let idx = timeIntervalIndexPath{
            
            deleteIndexArray.append(idx)
        }
        
        self.tableView.deleteRows(at: deleteIndexArray, with: UITableView.RowAnimation.bottom)
        
        ST_ConversationAdapter.shared.refresh_all_data()
    }
    
    func dismissMessageToolBar(){
        
        DTtoolBar?.removeFromSuperview()
        
        DTtoolBar = nil
    }
    
    func deleteBrowerImagesUUid(_ id:String){
        
        /*
         let q = dispatch_queue_global_t(label: "createBrowerQueue")
         
         q.sync() {
         
         var idx:Int?
         for (i,item) in self.originalImageUUIDArray.enumerated(){
         
         if item == id{
         idx = i
         break
         }
         }
         
         if let d = idx{
         
         self.originalImageUUIDArray.remove(at: d)
         
         self.originalImageArray.remove(at: d)
         }
         }
         */
        
    }
    
}



//MARK: - Const

let DTChatUserImageWidth:CGFloat = {
    return 40.0
}()

let DTChatEmojiWidth:CGFloat = {
    return 26.0
}()


let DTChatTextWidthMax:CGFloat = {
    return 500.0/750*ScreenWidth
}()

let DTChatTextFont:UIFont = {
    return UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.regular)
}()
let DTChatNickNameFont:UIFont = {
    return UIFont.init(name: "PingFangSC-Medium", size: 14)!
}()
let DTChatTimeFont:UIFont = {
    return UIFont.init(name: "PingFangSC-Regular", size: 12)!
}()




//MARK: - auto send msg
class ST_BTAutoSendMsg: NSObject {
    
    static let shared = ST_BTAutoSendMsg()
    
    private override init() {
        super.init()
    }
    
    func please_follow_me(accid:String,seconds:Int,msgCount:Int){
        
        
        main_thread_execute(afterDelay: TimeInterval(seconds)) {
            
            JVrequest(PH.secondsTalkApi,parameters: ["msg_total":msgCount,"target_accid":accid], success: { (json) in
                
                
                print("临时需求 发送:",json)
                
            }) { (code, err) in
                
                print("临时需求 发送失败:",err)
            }
            
        }
        
    }
    
    
}



/**
 全局聊天次数统计 每7次 发送一次请求
 */
fileprivate var CHAT_TIMES_MAP = [String:Int]()




/**
 是否展示过 聊天解锁
 */
class ST_BTChatSessioninfo: Object{
    
    @objc dynamic var chatSession = ""
    
    @objc dynamic var shipURL = ""
    
    override static func primaryKey() -> String? {
        return "chatSession"
    }
}
